package com.epam.xml.xmlimport;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.apache.log4j.Logger;
import org.apache.log4j.chainsaw.Main;

import com.epam.xml.bank.Account;
import com.epam.xml.bank.Card;
import com.epam.xml.bank.Client;

public class StaxParser {
	private List<Client> clients = new ArrayList<Client>();
	private Client currentClient = new Client();;
	private Account currentAccount = new Account();
	private Card card = new Card();
	private String currency;
	private int amount;
	private XMLEvent event;
	private XMLEventReader eventReader;
	private static Logger logger = Logger.getLogger(StaxParser.class);

	public void parseIt(String fileXML) {
		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
		try {
			eventReader = inputFactory.createXMLEventReader(Main.class
					.getClassLoader().getResourceAsStream(fileXML));

			while (eventReader.hasNext()) {
				event = eventReader.nextEvent();
				if (event.isStartElement()) {
					readAttributes();

					if (event.isStartElement()) {
						if (event.asStartElement().getName().getLocalPart()
								.equals("id")
								&& event.asStartElement().getName().getPrefix()
										.equals("p1")) {
							readFirstElement();
							continue;
						}
					}
					readOtherElements();
				}
				readEndElement();
			}
		} catch (XMLStreamException e) {
			logger.error(e);
		}
	}

	private void readAttributes() {
		StartElement startElement = event.asStartElement();
		if (startElement.getName().getLocalPart() == "client") {
			Iterator<Attribute> attributes = startElement.getAttributes();
			while (attributes.hasNext()) {
				Attribute attribute = attributes.next();
				switch (attribute.getName().toString()) {
				case "login":
					currentClient.setLogin(attribute.getValue());
					break;
				case "password":
					currentClient.setPassword(attribute.getValue());
					break;
				}
			}
		}
	}

	private void readFirstElement() throws XMLStreamException {
		event = eventReader.nextEvent();
		currentClient.setId(Integer.valueOf(event.asCharacters().getData()));
	}

	private void readOtherElements() throws XMLStreamException {
		switch (event.asStartElement().getName().getLocalPart()) {
		case "name":
			event = eventReader.nextEvent();
			currentClient.setName(event.asCharacters().getData());
			break;
		case "id":
			if (event.asStartElement().getName().getPrefix().equals("p1")) {
				currentClient.setId(Integer.valueOf(event.asCharacters()
						.getData()));
				break;
			}
			if (event.asStartElement().getName().getPrefix().equals("p2")) {
				event = eventReader.nextEvent();
				currentAccount.setId(Integer.valueOf(event.asCharacters()
						.getData()));
				break;
			}
		case "currency":
			event = eventReader.nextEvent();
			currency = event.asCharacters().getData();
			break;
		case "amount":
			event = eventReader.nextEvent();
			amount = Integer.valueOf(event.asCharacters().getData());
			break;
		case "cardType":
			event = eventReader.nextEvent();
			card.setCardType(event.asCharacters().getData());
			break;
		case "number":
			event = eventReader.nextEvent();
			card.setNumber(event.asCharacters().getData());
			break;
		case "pin":
			event = eventReader.nextEvent();
			card.setPin(event.asCharacters().getData());
			break;
		}
	}

	private void readEndElement() {
		if (event.isEndElement()) {
			EndElement endElement = event.asEndElement();
			if (endElement.getName().getLocalPart() == "account") {
				currentAccount.setCard(card);
				HashMap<String, Integer> currencyAndAmount = new HashMap<String, Integer>();
				currencyAndAmount.put(currency, amount);
				currentAccount.setCurrencyAndAmount(currencyAndAmount);
				currentClient.addAccount(currentAccount);
				currentAccount = new Account();
				card = new Card();
			}
			if (endElement.getName().getLocalPart() == "client") {
				clients.add(currentClient);
				currentClient = new Client();
			}
		}
	}

	public List<Client> getClients() {
		return clients;
	}

}
